﻿using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace SQLite
{
    internal static class ExSqliteDataReader
    {
        /// <summary>
        /// 将SqliteDataReader转为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static T To<T>(this SqliteDataReader reader)
        {
            if (reader != null)
            {
                var model = default(T);
                var type = typeof(T);
                //列特性
                var columnAttribute = type.GetColumnAttribute();

                //数据查询的列名集合
                var fileDictor = new Dictionary<string, int>();
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    fileDictor.Add(reader.GetName(i), i);
                }
                if (reader.Read())
                {
                    var sucess = true;
                    model = CreatMode<T>(reader, type, columnAttribute, fileDictor, out sucess);
                    if (sucess)
                    {
                        return model;
                    }
                }
            }
            return default(T);
        }
        /// <summary>
        /// 将SqliteDataReader转为集合对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this SqliteDataReader reader)
        {
            if (reader != null)
            {
                var model = default(T);
                var type = typeof(T);

                List<T> list = new List<T>();
                //列特性
                var columnAttribute = type.GetColumnAttribute();

                //数据查询的列名集合
                var fileDictor = new Dictionary<string, int>();
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    fileDictor.Add(reader.GetName(i), i);
                }
                while (reader.Read())
                {
                    var sucess = true;
                    model = CreatMode<T>(reader, type, columnAttribute, fileDictor, out sucess);
                    if (sucess)
                    {
                        list.Add(model);
                    }
                }
                return list;
            }
            return new List<T>();
        }

        /// <summary>
        /// 反射赋值
        /// </summary>
        /// <param name="pi"></param>
        /// <param name="vaule"></param>
        /// <returns></returns>
        private static object SetPropertyValueType(PropertyInfo pi, object vaule)
        {
            if (vaule == null)
            {
                return vaule;
            }
            if (pi != null)
            {
                if (pi.PropertyType != vaule.GetType())
                {
                    if (!pi.PropertyType.IsGenericType)
                    {  //非泛型
                        return ChangeType(vaule, pi.PropertyType);
                    }
                    else
                    {  //泛型Nullable<>
                        Type genericTypeDefinition = pi.PropertyType.GetGenericTypeDefinition();
                        if (genericTypeDefinition == typeof(Nullable<>))
                        {
                            return ChangeType(vaule, Nullable.GetUnderlyingType(pi.PropertyType));
                        }
                        return vaule;
                    }
                }
                else
                {
                    return vaule;
                }
            }
            return vaule;
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reader"></param>
        /// <param name="type"></param>
        /// <param name="columnAttribute"></param>
        /// <param name="fileDictor"></param>
        /// <param name="sucess"></param>
        /// <returns></returns>
        private static T CreatMode<T>(SqliteDataReader reader, Type type, List<ColumnAttribute> columnAttribute, Dictionary<string, int> fileDictor, out bool sucess)
        {
            T model = Activator.CreateInstance<T>();
            sucess = true;
            foreach (var item in columnAttribute)
            {
                if (fileDictor.ContainsKey(item.ColumnName))
                {//有该列
                    var drValue = reader.GetValue(fileDictor[item.ColumnName]);
                    var pi = type.GetProperty(item.FileName);
                    if (pi != null && pi.CanWrite && (drValue != null && !Convert.IsDBNull(drValue)))
                    {
                        try
                        {
                            pi.SetValue(model, SetPropertyValueType(pi, drValue), null);
                        }
                        catch (Exception)
                        {
                            sucess = false;
                        }
                    }
                }

            }
            return model;
        }


        private static object ChangeType(object value, Type type)
        {
            if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
            if (value == null) return null;
            if (type == value.GetType()) return value;
            if (type.IsEnum)
            {
                if (value is string)
                    return Enum.Parse(type, value as string);
                else
                    return Enum.ToObject(type, value);
            }
            if (!type.IsInterface && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                object innerValue = ChangeType(value, innerType);
                return Activator.CreateInstance(type, new object[] { innerValue });
            }
            if (value is string && type == typeof(Guid)) return new Guid(value as string);
            if (value is string && type == typeof(Version)) return new Version(value as string);
            if (!(value is IConvertible)) return value;
            return Convert.ChangeType(value, type);
        }


    }
}
